<!--
 * @Description: 项目权限-部分权限
 * @Author gong
 * @create 2024/9/6 14:32
 -->
<!--setup-->
<script setup>
import { computed, getCurrentInstance, onMounted, reactive, ref } from 'vue'
import SvgIcon from '@/components/svg-icon/index.vue' // svg组件
import AuthTable from './components/AuthTable.vue' // 授权表格
import AuthTree from './components/AuthTree.vue' // 授权部门树
import { eachTree, filterTree, groupBy, to, treeToList } from 'sf-utils2'
import { ElMessage } from 'element-plus'
import prjInfoApi from '@/api/modules/prj-info' // api接口

const { proxy } = getCurrentInstance()
const props = defineProps({
  baseInfo: {
    type: Object,
    default: () => ({})
  }
})
const emit = defineEmits([])

/* 状态 */
/**
 * 部门树
 */
const departmentTree = ref([])

/**
 * 未授权数据
 */
const unauthorized = reactive({
  treeRef: null, // 部门树实例
  tableRef: null, // 表格实例
  currentKey: null, // 当前选中的部门id
  empList: [] // 未授权用户列表
})

/**
 * 授权数据
 */
const authorized = reactive({
  treeRef: null, // 部门树实例
  tableRef: null, // 表格实例
  currentKey: null // 当前选中的部门id
})

/**
 * 授权用户map
 * 数据类型: {branchId: [{id: string, name: string}]}
 */
const authUserMap = ref({})

/* 方法 */
/**
 * 未授权部门树点击
 */
async function onUnauthNodeClick() {
}

/**
 * 授权部门树点击
 */
function onAuthNodeClick() {
  unauthorized.tableRef.clearCheckedRowList()
}

/**
 * 移动到右侧, 授权
 */
function onMoveToRight() {
  const unauthList = unauthorized.tableRef.checkedRowList

  if (!unauthList.length) return ElMessage.warning('请选择需要授权的用户')

  unauthList.forEach((emp) => {
    const branchId = emp.branchId

    // 初始化
    if (!authUserMap.value[branchId]) authUserMap.value[branchId] = []

    // 授权
    authUserMap.value[branchId].push(emp)
  })

  // 更新数据
  unauthorized.tableRef.clearCheckedRowList()

  // 设置默认选中
  if (!authorized.currentKey && unauthList.length) {
    authorized.currentKey = unauthList[0].branchId
  }
}

/**
 * 移动到左侧, 取消授权
 */
function onMoveToLeft() {
  const authList = authorized.tableRef.checkedRowList

  if (!authList.length) return ElMessage.warning('请选择需要取消授权的用户')

  const authIds = authList.map((item) => item.id)

  // 移除授权
  Object.keys(authUserMap.value).forEach((key) => {
    authUserMap.value[key] = authUserMap.value[key].filter((item) => !authIds.includes(item.id))
  })

  // 更新数据
  authorized.tableRef.clearCheckedRowList()
}

/**
 * 请求部门树列表
 */
async function requestDepartmentTree() {
  // 首先获取部门列表， 后面还会用到
  const [res, err] = await to(ucEmployeeInfoApi.queryCfBranchList())
  if (err || res?.code !== 200) return ElMessage.error(res?.message || String(err))

  departmentTree.value = res.data

  const rootNode = departmentTree.value?.at(0)

  if (!rootNode) return

  unauthorized.currentKey = rootNode.id
  onUnauthNodeClick(rootNode)
}

/**
 * 请求用户列表
 */
async function requestUserList() {
  const [res, err] = await to(prjInfoApi.getPrjPerUserList({ prjId: props.baseInfo.id }))
  if (err || res?.code !== 200) return ElMessage.error(res?.message || String(err))

  // 没有数据, 不需要后续处理
  if (!res.data.length) return

  const deptIds = treeToList({ tree: departmentTree.value }).map((dept) => dept.id)

  // 数据转换
  const userList = res.data
    // 过滤掉不在部门下的数据
    .filter((user) => deptIds.includes(user.deptId + ''))
    .map((item) => {
      return {
        branchId: item.deptId,
        id: item.userId,
        mobile: item.mobile,
        empName: item.userName,
        roleList: item.roleName?.split(',')?.map((item) => ({ roleName: item })) ?? []
      }
    })

  // 分组
  authUserMap.value = groupBy(userList, 'branchId')

  // 设置默认选中
  const rootNode = departmentTree.value?.at(0)
  if (!rootNode) return
  // 设置默认选中
  authorized.currentKey = rootNode.id
}

/* 计算 */
/**
 * 未授权部门树
 * 排除掉已授权的数据就是 未授权的数据
 */
const _unauthTree = computed(() => {
  return eachTree({
    tree: departmentTree.value,
    traversalOrder: 'postorder',
    callbackItem: (node) => {
      // 重置count, 子节点已经在这里处理过了， 所有后面直接累加即可
      node.empCount -= authUserMap.value[node.id]?.length ?? 0

      // 计算总数 (包括子节点)
      node.empCount += node.children.reduce((acc, cur) => acc + cur.empCount, 0)
    }
  })
})

/**
 * 未授权用户
 * @private
 */
const _unauthUsers = computed(() => {
  // 查找到当前要展示的数据
  const unauthUsers = unauthorized.empList

  // 授权的用户
  const userMap = Object.values(authUserMap.value)
    .flatMap((item) => item)
    .reduce((acc, cur) => {
      acc[cur.id] = cur
      return acc
    }, {})
  // 过滤掉已授权的用户
  return unauthUsers.filter((item) => !userMap[item.id])
})

/**
 * 未授权用户数量
 */
const _unauthCount = computed(() => {
  return _unauthTree.value?.[0]?.empCount ?? 0
})

/**
 * 授权部门树
 */
const _authTree = computed(() => {
  return filterTree({
    tree: departmentTree.value,
    traversalOrder: 'postorder',
    callbackItem: (node) => {
      node.empCount = authUserMap.value[node.id]?.length ?? 0

      // 计算总数
      node.empCount += node.children.reduce((acc, cur) => {
        // 已授权用户数量
        const authCount = authUserMap.value[cur.id]?.length ?? 0

        return acc + authCount
      }, 0)

      return node.empCount > 0
    }
  })
})

/**
 * 授权用户
 */
const _authUsers = computed(() => {
  // 判断是不是根目录
  const rootId = departmentTree.value?.[0]?.id

  // 如果是根目录, 直接返回所有的用户
  if (authorized.currentKey === rootId) return Object.values(authUserMap.value).flat()

  return authUserMap.value[authorized.currentKey] ?? []
})

/**
 * 授权用户数量
 */
const _authCount = computed(() => {
  return Object.values(authUserMap.value).flat().length
})

/* 监听 */

/* 周期 */
onMounted(async () => {
  // 然后请求项目授权数据，然后踢掉不在部门下的数据
  await requestDepartmentTree()

  // 获取项目授权数据
  await requestUserList()
})

/* 暴露 */
defineExpose({
  $: proxy.$,
  getUserList() {
    const userList = Object.values(authUserMap.value).flat()

    if (!userList.length) {
      ElMessage.warning('请先授权用户')
      throw new Error('请先授权用户')
    }

    return userList
  }
})
</script>

<!--render-->
<template>
  <div class="flex w-full flex-1 overflow-hidden">
    <!-- 内容区 -->
    <div class="border-1 flex min-w-0 flex-1 flex-col rounded border">
      <div
        class="h-48px border-b-1 flex flex-none items-center justify-between border-b px-4 text-sm text-text-tertiary"
      >
        <h2>未授权用户名单</h2>
        <p>当前列表：{{ _unauthUsers.length }} / {{ _unauthCount }}</p>
      </div>
      <div class="flex flex-1 overflow-hidden">
        <AuthTree
          :ref="(el) => (unauthorized.treeRef = el)"
          v-model:current-key="unauthorized.currentKey"
          class="w-180px border-r-1 min-h-0 flex-none border-r p-2"
          :tree-data="_unauthTree"
          @node-click="onUnauthNodeClick"
        />
        <AuthTable
          :ref="(el) => (unauthorized.tableRef = el)"
          class="min-w-0 flex-1 p-4"
          :data="_unauthUsers"
        />
      </div>
    </div>
    <div class="flex flex-none flex-col justify-center gap-4 px-5">
      <el-button
        type="primary"
        class="w-32px"
        @click="onMoveToRight"
      >
        <SvgIcon
          svg="approval/arrow-right"
          size="16px"
        />
      </el-button>
      <el-button
        type="primary"
        class="w-32px !ml-0"
        @click="onMoveToLeft"
      >
        <SvgIcon
          svg="approval/arrow-left"
          size="16px"
        />
      </el-button>
    </div>
    <div class="border-1 flex min-w-0 flex-1 flex-col rounded border">
      <div
        class="h-48px border-b-1 flex flex-none items-center justify-between border-b px-4 text-sm text-text-tertiary"
      >
        <h2>已授权用户名单</h2>
        <p>当前列表：{{ _authUsers.length }} / {{ _authCount }}</p>
      </div>
      <div class="flex flex-1 overflow-hidden">
        <AuthTree
          :ref="(el) => (authorized.treeRef = el)"
          v-model:current-key="authorized.currentKey"
          class="w-180px border-r-1 h-full flex-none border-r p-2"
          :tree-data="_authTree"
          @node-click="onAuthNodeClick"
        />
        <AuthTable
          :ref="(el) => (authorized.tableRef = el)"
          class="min-w-0 flex-1 p-4"
          :data="_authUsers"
        />
      </div>
    </div>
  </div>
</template>

<!--style-->
<style scoped lang="less"></style>
